import { RegisterComponent } from "@feng3d/ecs";
import { ColorRepresentation, textureEncodingNames, textureEncodingValues, Vector2, WebGLRenderer, WebGLRendererParameters } from "../../thirdparty/three/imports";
import { Camera3D } from "../cameras/Camera3D";
import { Component3D } from "../core/Component3D";
import { Scene3D } from "../scenes/Scene3D";
import { Texture3D } from "../textures/Texture3D";
import { WebGLShadowMap3D } from "./webgl/WebGLShadowMap3D";
import { WebGLRenderTarget3D } from "./WebGLRenderTarget3D";

declare module "@feng3d/ecs"
{
    interface ComponentMap { WebGLRenderer3D: WebGLRenderer3D; }
}

/**
 * 3D渲染器，包装`three`中`WebGLRenderer`
 */
@RegisterComponent({ name: 'WebGLRenderer3D' })
export class WebGLRenderer3D extends Component3D
{
    /**
     * @private
     */
    _webGLRenderer: WebGLRenderer;

    get size()
    {
        this._webGLRenderer?.getSize(this._size);

        return this._size;
    }
    set size(v)
    {
        this._size.set(v.x, v.y);
        this._webGLRenderer?.setSize(this._size.width, this._size.height);
    }
    private _size = new Vector2();

    get pixelRatio()
    {
        if (this._webGLRenderer)
        {
            this._pixelRatio = this._webGLRenderer.getPixelRatio();
        }

        return this._pixelRatio;
    }
    set pixelRatio(v)
    {
        this._pixelRatio = v;
        this._webGLRenderer?.setPixelRatio(v);
    }
    private _pixelRatio: number;

    get domElement()
    {
        return this._webGLRenderer.domElement;
    }

    get outputEncoding()
    {
        return textureEncodingNames[this._webGLRenderer.outputEncoding];
    }

    set outputEncoding(v)
    {
        this._webGLRenderer.outputEncoding = textureEncodingValues[v];
    }

    get physicallyCorrectLights()
    {
        return this._webGLRenderer.physicallyCorrectLights;
    }

    set physicallyCorrectLights(v)
    {
        this._webGLRenderer.physicallyCorrectLights = v;
    }

    get shadowMap()
    {
        const webGLShadowMap3D = WebGLShadowMap3D.get(this._webGLRenderer.shadowMap);

        return webGLShadowMap3D;
    }

    set shadowMap(v)
    {
        this._webGLRenderer.shadowMap = v._webGLShadowMap;
    }

    get autoClear()
    {
        return this._webGLRenderer.autoClear;
    }

    set autoClear(v)
    {
        this._webGLRenderer.autoClear = v;
    }

    get clippingPlanes()
    {
        return this._webGLRenderer.clippingPlanes;
    }
    set clippingPlanes(v)
    {
        this._webGLRenderer.clippingPlanes = v;
    }

    get localClippingEnabled()
    {
        return this._webGLRenderer.localClippingEnabled;
    }
    set localClippingEnabled(v)
    {
        this._webGLRenderer.localClippingEnabled = v;
    }

    get capabilities()
    {
        return this._webGLRenderer.capabilities;
    }
    set capabilities(v)
    {
        this._webGLRenderer.capabilities = v;
    }

    get extensions()
    {
        return this._webGLRenderer.extensions;
    }
    set extensions(v)
    {
        this._webGLRenderer.extensions = v;
    }

    /**
     * WebGLRenderer初始参数。
     *
     * 注：只在初始化时生效。
     */
    parameters?: WebGLRendererParameters;

    init()
    {
        super.init();

        this._webGLRenderer = new WebGLRenderer(this.parameters);
        if (this._size.lengthSq() > 0)
        {
            this._webGLRenderer.setSize(this._size.width, this._size.height);
        }
        if (this._pixelRatio !== undefined)
        {
            this._webGLRenderer?.setPixelRatio(this._pixelRatio);
        }
    }

    destroy(): void
    {
        this._webGLRenderer = null;

        super.destroy();
    }

    render(scene: Scene3D, camera: Camera3D)
    {
        // 修复渲染前更新摄像机矩阵数据
        // @see https://github.com/mrdoob/three.js/blob/r149/src/renderers/WebGLRenderer.js#L963
        camera.updateMatrixWorld();
        //
        this._webGLRenderer.render(scene._scene, camera._camera);
    }

    clear()
    {
        this._webGLRenderer.clear();
    }

    clearDepth()
    {
        this._webGLRenderer.clearDepth();
    }

    setPixelRatio(value: number)
    {
        this._webGLRenderer.setPixelRatio(value);
    }

    setSize(width: number, height: number, updateStyle?: boolean)
    {
        this._webGLRenderer.setSize(width, height, updateStyle);
    }

    setViewport(x: number, y?: number, width?: number, height?: number)
    {
        this._webGLRenderer.setViewport(x, y, width, height);
    }

    setClearColor(color: ColorRepresentation, alpha?: number)
    {
        this._webGLRenderer.setClearColor(color, alpha);
    }

    setRenderTarget(renderTarget: WebGLRenderTarget3D, activeCubeFace?: number, activeMipmapLevel?: number)
    {
        this._webGLRenderer.setRenderTarget(renderTarget ? renderTarget._target : null, activeCubeFace, activeMipmapLevel);
    }

    clearStencil()
    {
        this._webGLRenderer.clearStencil();
    }

    getPixelRatio()
    {
        return this._webGLRenderer.getPixelRatio();
    }

    copyFramebufferToTexture(position: Vector2, texture: Texture3D, level?: number)
    {
        this._webGLRenderer.copyFramebufferToTexture(position, texture._texture, level);
    }
}
